﻿using System.IO.Ports;

namespace Zhaoxi.CommunicationLesson
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");

            //Modbus0x03();
            //Modbus0x06();
            //Modbus0x10();
            Modbus0x01();

            Console.ReadLine();
        }

        static void Modbus0x03()
        {
            // 需要通过03功能获取对应的设备中的存储数据
            // 
            // ModbusRTU  ->  串口    物理接口
            SerialPort serialPort = new SerialPort("COM1");
            serialPort.Open();

            //
            ushort addr = 302;
            byte[] bytes = new byte[] {
                1,
                3,
                (byte)(addr/256),(byte)(addr%256),   // 一个字节，无符号的情况：255     需要另一个字节支持  65535
                        // 0000 0001   0000  0000         0x0A   ->  10
                0,2,
                0,0// 用来接收CRC16的校验码结果
            };
            CRC16(bytes);
            // 请求发送
            serialPort.Write(bytes, 0, bytes.Length);

            // 接收对方的响应信息
            byte[] bytes2 = new byte[serialPort.BytesToRead];
            serialPort.Read(bytes2, 0, bytes2.Length);

            float v = BitConverter.ToSingle(new byte[] {
                bytes2[6], bytes2[5], bytes2[4], bytes2[3] });
            Console.WriteLine(v);

            return;
            // 这里4台设备，接到一个串口，程序运行获取多个设备
            // 485通信：半双工
            // 轮询
            Task.Run(async () =>
            {
                byte id = 1;
                while (true)
                {
                    byte[] bytes = new byte[] {
                        id,
                        3,
                        0,0,   // 一个字节，无符号的情况：255     需要另一个字节支持  65535
                               // 0000 0001   0000  0000         0x0A   ->  10
                        0,2,
                        0,0// 用来接收CRC16的校验码结果
                    };
                    id = (byte)(++id > 4 ? 1 : id);
                    CRC16(bytes);
                    // 请求发送
                    serialPort.Write(bytes, 0, bytes.Length);

                    await Task.Delay(100);
                    // 接收对方的响应信息
                    byte[] bytes2 = new byte[serialPort.BytesToRead];
                    serialPort.Read(bytes2, 0, bytes2.Length);


                    // 检查：校验   略过

                    byte[] data_byte_1 = new byte[] { bytes2[3], bytes2[4] };
                    byte[] data_byte_2 = new byte[] { bytes2[5], bytes2[6] };

                    var data_1 = bytes2[3] * 256 + bytes2[4];
                    var data_2 = bytes2[5] * 256 + bytes2[6];

                    await Console.Out.WriteLineAsync($"{id} : 温度 {data_1}  -  湿度 {data_2}");
                    await Task.Delay(1000);
                }

            });
        }

        static void Modbus0x06()
        {
            SerialPort serialPort = new SerialPort("COM1");
            serialPort.Open();

            ushort addr = 305;
            //UInt16 value = 888;
            float value = 6.5f;
            byte[] bytes = new byte[] {
                0x01,
                0x06,
                (byte)(addr/256),(byte)(addr%256),
                (byte)(value/256),(byte)(value%256),
                0,0
            };
            CRC16(bytes);

            // 请求发送
            serialPort.Write(bytes, 0, bytes.Length);

        }

        static void Modbus0x10()
        {
            SerialPort serialPort = new SerialPort("COM1");
            serialPort.Open();

            ushort addr = 302;
            //UInt16 value = 888;
            float value = 6.5f;
            byte[] v_bytes = BitConverter.GetBytes(value);
            byte[] bytes = new byte[] {
                0x01,
                0x10,
                (byte)(addr/256),(byte)(addr%256),
                0x00,0x02,// 写入连续的2个寄存器
                0x04,// 写入对应寄存器的数据字节数
                v_bytes[3],
                v_bytes[2],
                v_bytes[1],
                v_bytes[0],
                0,0
            };
            CRC16(bytes);

            // 请求发送
            serialPort.Write(bytes, 0, bytes.Length);

        }

        static void Modbus0x01()
        {
            SerialPort serialPort = new SerialPort("COM1");
            serialPort.Open();

            byte[] bytes = new byte[] {
                0x01,
                0x01,
                0x00,30,
                0x00,0x14,
                0,0
            };
            CRC16(bytes);

            // 请求发送
            serialPort.Write(bytes, 0, bytes.Length);

            byte[] bytes2 = new byte[serialPort.BytesToRead];
            serialPort.Read(bytes2, 0, bytes2.Length);

            for (int i = 3; i < 6; i++)
            {
                // 1  --  0000 0001
                // 2  --  0000 0010
                // 4  --  0000 0100
                // 8  --  0000 1000
                for (int s = 0; s < 8; s++)
                {
                    bool state = (bytes2[i] & (1 << s)) > 0;
                    Console.WriteLine(state);
                }
                //bool state = (bytes2[i] & 2) > 0;
                //bool state = (bytes2[i] & 4) > 0;
                //bool state = (bytes2[i] & 8) > 0;
                //bool state = (bytes2[i] & 16) > 0;
                //bool state = (bytes2[i] & 32) > 0;
            }
        }

        // float  32   一个寄存器：无符号    65535
        // 1byte   :  byte
        // 2bytes  :  ushort  short  uint16   int16
        // 4bytes  :  int  uint  int32  uint32  float
        // 8bytes  :  double
        // 状态   开关量    true  false   0   1

        // 310地址：16个状态  0000 0000   0000 0000
        // I0.0 - I0.7
        // 123  -  00 7B  - 0000 0000  0110 1011
        //  16     00 10  & 0000 0000  0001 0000
        //                = 0000 0000  0000 0000  > 0  True
        // 123 & 16 > 0

        static void CRC16(byte[] value)
        {
            if (value == null || !value.Any())
                throw new ArgumentException("");

            //运算
            ushort crc = 0xFFFF;
            for (int i = 0; i < value.Length - 2; i++)
            {
                crc = (ushort)(crc ^ (value[i]));
                for (int j = 0; j < 8; j++)
                {
                    crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
                }
            }
            byte hi = (byte)((crc & 0xFF00) >> 8);  //高位置
            byte lo = (byte)(crc & 0x00FF);         //低位置


            value[value.Length - 2] = lo;
            value[value.Length - 1] = hi;
        }
    }
}
